package org.youyun56.gpsserver.net;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.util.Calendar;
import java.util.Properties;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.apache.log4j.Logger;
import org.apache.log4j.xml.DOMConfigurator;
import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.LineDelimiter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.transport.socket.SocketSessionConfig;
import org.apache.mina.transport.socket.nio.NioSession;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import org.youyun56.gpsserver.CacheFactory;
import org.youyun56.gpsserver.Config;
import org.youyun56.gpsserver.apache.tomcat.TomcatServer;
import org.youyun56.gpsserver.command.RealWorker;
import org.youyun56.gpsserver.common.JSONUtils;
import org.youyun56.gpsserver.common.PathConfig;
import org.youyun56.gpsserver.plugins.WangLangGood;

public class GpsServer extends RealWorker {
    public static Properties props = new Properties();
    public final static Logger log = Logger.getLogger(GpsServer.class);
    public static NioSocketAcceptor acceptor;
    public final static int bufferSize = 1024 * 512;
    private ScheduledExecutorService wangLangScheduleService;
    private ScheduledExecutorService goodKiller;
    private ScheduledExecutorService sessionCheckerService;

    private static void loadConfig() throws FileNotFoundException, IOException {
        props.load(new FileInputStream(PathConfig.ROOT + "/config.properties"));
    }

    @Override
    public void run() throws Exception {
        super.run();
        try {
            startGpsService();
            startSessionChecker();
            TomcatServer.start();
            startWangLangGoodCatch();
            startGoodKiller();
            log.info("Listening on port " + Integer.parseInt(GpsServer.props.getProperty(Config.SocketPort)));
        }
        catch (Exception e) {
            log.error(e.getMessage(), e);
            log.error("server started failure!");
        }
    }

    private void startSessionChecker() {
        // TODO Auto-generated method stub
        sessionCheckerService = Executors.newSingleThreadScheduledExecutor();
        sessionCheckerService.scheduleAtFixedRate(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                writeTestObjToSession();
            }

            private void writeTestObjToSession() {
                // TODO Auto-generated method stub
                for (IoSession ioSession : GpsServer.acceptor.getManagedSessions().values()) {
                    NioSession session = (NioSession) ioSession;
                    try {
                        session.write(JSONUtils.test());
                    }
                    catch (Exception e) {
                        session.close(true);
                    }
                }
            }
        }, 1, 1, TimeUnit.MINUTES);
    }

    private void startGoodKiller() {
        Calendar c = Calendar.getInstance();
        int hour = c.get(Calendar.HOUR_OF_DAY);
        goodKiller = Executors.newSingleThreadScheduledExecutor();
        goodKiller.scheduleAtFixedRate(new GoodKiller(), 25 - hour, 24, TimeUnit.HOURS);
    }

    private void startWangLangGoodCatch() {
        wangLangScheduleService = Executors.newSingleThreadScheduledExecutor();
        wangLangScheduleService.scheduleWithFixedDelay(new WangLangGood(), 0, 5, TimeUnit.SECONDS);
    }

    @Override
    public void shutdown() {
        acceptor.dispose();
        wangLangScheduleService.shutdownNow();
        TomcatServer.shutDownNow();
        CacheFactory.instance.shutdown();
        try {
            br.close();
        }
        catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private void startGpsService() throws Exception, FileNotFoundException, IOException {
        acceptor = new NioSocketAcceptor();
        acceptor.setReuseAddress(true);
        DefaultIoFilterChainBuilder chain = acceptor.getFilterChain();
        TextLineCodecFactory textLineCodecFactory = new TextLineCodecFactory(Charset.forName("utf-8"), LineDelimiter.UNIX, LineDelimiter.UNIX);
        textLineCodecFactory.setEncoderMaxLineLength(bufferSize);
        chain.addLast("codec", new ProtocolCodecFilter(textLineCodecFactory));
        SocketSessionConfig config = acceptor.getSessionConfig();
        config.setIdleTime(IdleStatus.BOTH_IDLE, 10);
        config.setKeepAlive(true);
        config.setSoLinger(0);
        config.setReceiveBufferSize(bufferSize);
        config.setSendBufferSize(bufferSize);
        acceptor.setHandler(new GpsHandler());
        GpsServer.loadConfig();
        acceptor.bind(new InetSocketAddress(Integer.parseInt(GpsServer.props.getProperty(Config.SocketPort))));
        CacheFactory.start();
    }

    public static void main(String[] args) throws Exception {
        System.setProperty("server", "gpsserver");
        DOMConfigurator.configure(PathConfig.ROOT + "/log4j.xml");
        new GpsServer();
    }
}
